package backend

import (
	models "awesomeProject1/models/pojo"
	servModels "awesomeProject1/models/service"
	"awesomeProject1/pkg/e"
	"awesomeProject1/pkg/gintool"
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/simplechain-org/client/log"
	"os"
	"time"
)

func (b *backend) run(ctx *gin.Context) {
	myLoanDetailsList, hasEnded := b.getLoanDetailsList(ctx)
	if hasEnded {
		return
	}

	//获取原始的总行支行关系映射表数据
	orgMappingList, hasEnded := b.getOrgMappingList(ctx)
	if hasEnded {
		return
	}

	//获取2023-7-21到20203-8-21收到的转账详情数据列表
	transferDetailsList, hasEnded := b.getTransferDetailsList(ctx, myLoanDetailsList)
	if hasEnded {
		return
	}

	//将总行支行关系映射表数据保存到文件
	hasEnded = b.saveOrgMappingListToFile(ctx, orgMappingList, "./originalOrgMappingList-1.txt")
	if hasEnded {
		return
	}

	//将转账详情数据保存到文件
	hasEnded = b.saveTransferDetailsToFile(ctx, transferDetailsList, "./originalTransferDetailsList-2.txt")
	if hasEnded {
		return
	}

	//分析转账详情数据，获取总行支行之间的对应关系
	orgMappingOfTransferDetailList, hasEnded := b.analysisTransferDetails(ctx, transferDetailsList)
	if hasEnded {
		return
	}

	//将从转账详情获取到的总行支行之间的对应关系保存到文件
	hasEnded = b.saveOrgMappingOfTransferDetailListToFile(ctx, orgMappingOfTransferDetailList, "./orgMappingOfTransferDetailList-3.txt")
	if hasEnded {
		return
	}

	////获取待添加进总行支行关系映射表中的记录
	toBeAddedOrgMappingList, hasEnded := b.getToBeAddedOrgMappingRecords(ctx, orgMappingList, orgMappingOfTransferDetailList)
	if hasEnded {
		return
	}

	//将待添加进总行支行关系映射表中的记录保存到文件
	hasEnded = b.saveBeAddedOrgMappingRecordsToFile(ctx, toBeAddedOrgMappingList, "./toBeAddedOrgMappingRecords-4.txt")
	if hasEnded {
		return
	}

	gintool.ResultOk(ctx)
	return
}

func (b *backend) getLoanDetailsList(ctx *gin.Context) (myLoanDetailsList []*models.MyLoanDetails, hasEnded bool) {
	myLoanDetailsList = make([]*models.MyLoanDetails, 0, 1000)

	startTime, err := time.ParseInLocation("20060102", "20230721", time.Local)
	if err != nil {
		log.Error(err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	endTime, err := time.ParseInLocation("20060102", "20230822", time.Local)
	if err != nil {
		log.Error(err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}

	for i := 1; ; i++ {
		list, total, code := b.detailServ.GetTransDetailsList(startTime, endTime, gintool.CreatePager(i, 10000))
		if code != e.Ok {
			log.Error("获取详情备份数据错误", "errInfo", e.GetMsg(code))
			gintool.ResultCode(ctx, code)
			hasEnded = true
			return
		}
		if len(list) == 0 {
			break
		}
		if i > 1000 {
			log.Error("获取详情备份数据过多", "total", total)
			hint := fmt.Sprintln("获取详情备份数据过多, total=", total)
			gintool.ResultCodeWithData(ctx, e.Error, hint)
			hasEnded = true
			return
		}
		myLoanDetailsList = append(myLoanDetailsList, list...)
	}
	return
}

//获取总行支行关系映射表数据
func (b *backend) getOrgMappingList(ctx *gin.Context) (orgMappingList []*models.LoanOrg, hasEnded bool) {
	orgMappingList = make([]*models.LoanOrg, 0, 1000)
	for i := 1; ; i++ {
		list, total, code := b.detailServ.GetOrgMappingList(gintool.CreatePager(i, 1000))
		if code != e.Ok {
			log.Error("获取总行支行关系表数据发生错误", "errInfo", e.GetMsg(code))
			gintool.ResultCode(ctx, code)
			return
		}
		if len(list) == 0 {
			break
		}
		if i > 1000 {
			log.Error("获取总行支行关系表数据量过多", "total", total)
			hint := fmt.Sprintln("获取总行支行关系表数据量过多, total=", total)
			gintool.ResultCodeWithData(ctx, e.Error, hint)
		}
		orgMappingList = append(orgMappingList, list...)
	}
	return
}

//获取2023-7-21到20203-8-21收到的转账详情数据列表
func (b *backend) getTransferDetailsList(ctx *gin.Context, myLoanDetailsList []*models.MyLoanDetails) (transferDetailsList []*models.TransactionDetail, hasEnded bool) {
	transferDetailsList = make([]*models.TransactionDetail, 0, len(myLoanDetailsList))
	for _, myLoanDetails := range myLoanDetailsList {
		temp := &models.TransactionDetail{}
		err := json.Unmarshal([]byte(myLoanDetails.TransferDetails), temp)
		if err != nil {
			log.Error("解析转账详情对象失败", "myLoanDetails.TransferDetails", myLoanDetails.TransferDetails, "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.DeSerializeObjErr, err.Error())
			hasEnded = true
			return
		}
		transferDetailsList = append(transferDetailsList, temp)
	}
	return
}

//将总行支行关系映射表数据保存到文件
func (b *backend) saveOrgMappingListToFile(ctx *gin.Context, orgMappingList []*models.LoanOrg, fileName string) (hasEnded bool) {
	file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Error("文件创建失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	//及时关闭file句柄
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			log.Error("文件关闭失败", "fileName", fileName, "err", err.Error())
		}
	}(file)
	//写入文件时，使用带缓存的 *Writer
	write := bufio.NewWriter(file)
	{
		content := "orgMapping.ID\t orgMapping.OrgId\t orgMapping.SubOrgId\t orgMapping.Type\t orgMapping.CreatedAt\n"
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}
	for _, orgMapping := range orgMappingList {
		content := fmt.Sprintf("%v\t%v\t%v\t%v\t%v\n", orgMapping.ID, orgMapping.OrgId, orgMapping.SubOrgId, orgMapping.Type, orgMapping.CreatedAt)
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}

	//Flush将缓存的文件真正写入到文件中
	err = write.Flush()
	if err != nil {
		log.Error("文件缓存数据写入磁盘失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	return
}

//将转账详情数据保存到文件
func (b *backend) saveTransferDetailsToFile(ctx *gin.Context, transferDetailsList []*models.TransactionDetail, fileName string) (hasEnded bool) {
	file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Error("文件创建失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	//及时关闭file句柄
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			log.Error("文件关闭失败", "fileName", fileName, "err", err.Error())
		}
	}(file)
	//写入文件时，使用带缓存的 *Writer
	write := bufio.NewWriter(file)
	{
		content := "detail.ReceiptIDHash\t detail.BankID\t detail.BankName\t detail.CounterpartyBankID\t detail.CounterpartyBank\n"
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}
	for _, transferDetail := range transferDetailsList {
		detail := transferDetail.Detail
		content := fmt.Sprintf("%v\t%v\t%v\t%v\t%v\n", detail.ReceiptIDHash, detail.BankID, detail.BankName, detail.CounterpartyBankID, detail.CounterpartyBank)
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}

	//Flush将缓存的文件真正写入到文件中
	err = write.Flush()
	if err != nil {
		log.Error("文件缓存数据写入磁盘失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	return
}

//分析转账详情数据，获取总行支行之间的对应关系
func (b *backend) analysisTransferDetails(ctx *gin.Context, transferDetailsList []*models.TransactionDetail) (
	orgMappingOfTransferDetailList []servModels.OrgMappingOfTransferDetailList, hasEnded bool) {
	capacity := len(transferDetailsList)
	orgMappingOfTransferDetailList = make([]servModels.OrgMappingOfTransferDetailList, capacity)

	//获取转账详情列表中的付款行行名列表
	payingBankNames := getBankNames(transferDetailsList)
	//通过支行名获取总行信息
	orgMappingInfoList := b.FindOrgInfo(payingBankNames)

	//检查相关列表数据是否可以一一对应
	if capacity != len(orgMappingInfoList) {
		hint := "内部错误，查询到的数据异常，各个列表长度不一致"
		log.Error(hint)
		gintool.ResultCodeWithData(ctx, e.Error, hint)
		hasEnded = true
		return
	}

	//拼装数据,返回结果
	for i := 0; i < capacity; i++ {
		orgMappingOfTransferDetailList[i].ReceiptIDHash = transferDetailsList[i].Detail.ReceiptIDHash
		orgMappingOfTransferDetailList[i].SubOrgId = transferDetailsList[i].Detail.BankID
		orgMappingOfTransferDetailList[i].SubOrgName = transferDetailsList[i].Detail.BankName
		//检查数据是否出错
		if transferDetailsList[i].Detail.BankName != orgMappingInfoList[i].SubOrgName {
			hint := "内部错误，列表匹配数据不一致"
			log.Error(hint)
			gintool.ResultCodeWithData(ctx, e.Error, hint)
			hasEnded = true
			return
		}
		orgMappingOfTransferDetailList[i].OrgId = orgMappingInfoList[i].OrgID
		orgMappingOfTransferDetailList[i].OrgName = orgMappingInfoList[i].OrgName
	}

	return
}

//将转账详情数据保存到文件
func (b *backend) saveOrgMappingOfTransferDetailListToFile(ctx *gin.Context,
	orgMappingOfTransferDetailList []servModels.OrgMappingOfTransferDetailList,
	fileName string) (hasEnded bool) {
	file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Error("文件创建失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	//及时关闭file句柄
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			log.Error("文件关闭失败", "fileName", fileName, "err", err.Error())
		}
	}(file)
	//写入文件时，使用带缓存的 *Writer
	write := bufio.NewWriter(file)
	{
		content := "ReceiptIDHash\t OrgId\t OrgName\t SubOrgId\t SubOrgName\n"
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}
	for _, orgMappingOfTransferDetail := range orgMappingOfTransferDetailList {
		content := fmt.Sprintf("%v\t%v\t%v\t%v\t%v\n",
			orgMappingOfTransferDetail.ReceiptIDHash,
			orgMappingOfTransferDetail.OrgId,
			orgMappingOfTransferDetail.OrgName,
			orgMappingOfTransferDetail.SubOrgId,
			orgMappingOfTransferDetail.SubOrgName)
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}

	//Flush将缓存的文件真正写入到文件中
	err = write.Flush()
	if err != nil {
		log.Error("文件缓存数据写入磁盘失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	return
}

//获取待添加进总行支行关系映射表中的记录
func (b *backend) getToBeAddedOrgMappingRecords(ctx *gin.Context,
	originalOrgMappingList []*models.LoanOrg,
	orgMappingOfTransferDetailList []servModels.OrgMappingOfTransferDetailList) (
	toBeAddedOrgMappingList []*models.LoanOrg,
	hasEnded bool) {

	toBeAddedOrgMappingList = make([]*models.LoanOrg, 0)

	//去除掉支行重复的数据后的转账详情数据
	var targetTransferDetailList []servModels.OrgMappingOfTransferDetailList
	tempMap := map[string]struct{}{}
	for _, transferDetail := range orgMappingOfTransferDetailList {
		_, has := tempMap[transferDetail.SubOrgId]
		if !has {
			targetTransferDetailList = append(targetTransferDetailList, transferDetail)
			tempMap[transferDetail.SubOrgId] = struct{}{}
		}
	}

label:
	for _, myLoanDetail := range targetTransferDetailList {
		//如果支行在原表中存在映射关系，跳过这条数据
		for _, originalOrgMapping := range originalOrgMappingList {
			if myLoanDetail.SubOrgId == originalOrgMapping.SubOrgId {
				continue label
			}
		}
		toBeAddedOrgMappingList = append(toBeAddedOrgMappingList, &models.LoanOrg{
			OrgId:     myLoanDetail.OrgId,
			SubOrgId:  myLoanDetail.SubOrgId,
			Type:      7,
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
		})
	}
	return
}

//将待添加进总行支行关系映射表中的记录保存到文件
func (b *backend) saveBeAddedOrgMappingRecordsToFile(ctx *gin.Context,
	toBeAddedOrgMappingList []*models.LoanOrg,
	fileName string) (hasEnded bool) {
	file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Error("文件创建失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	//及时关闭file句柄
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
			log.Error("文件关闭失败", "fileName", fileName, "err", err.Error())
		}
	}(file)
	//写入文件时，使用带缓存的 *Writer
	write := bufio.NewWriter(file)
	{
		content := "ID\t OrgId\t SubOrgId\t Type\t CreatedAt\n"
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}
	for _, orgMappingOfTransferDetail := range toBeAddedOrgMappingList {
		content := fmt.Sprintf("%v\t%v\t%v\t%v\t%v\n",
			orgMappingOfTransferDetail.ID,
			orgMappingOfTransferDetail.OrgId,
			orgMappingOfTransferDetail.SubOrgId,
			orgMappingOfTransferDetail.Type,
			orgMappingOfTransferDetail.CreatedAt)
		_, err = write.WriteString(content)
		if err != nil {
			log.Error("文件写入数据失败", "fileName", fileName, "content", "content", "err", err.Error())
			gintool.ResultCodeWithData(ctx, e.Error, err.Error())
			hasEnded = true
			return
		}
	}

	//Flush将缓存的文件真正写入到文件中
	err = write.Flush()
	if err != nil {
		log.Error("文件缓存数据写入磁盘失败", "fileName", fileName, "err", err.Error())
		gintool.ResultCodeWithData(ctx, e.Error, err.Error())
		hasEnded = true
		return
	}
	return
}

//获取转账详情列表中的付款行行名
func getBankNames(transferDetailsList []*models.TransactionDetail) (payingBankNames []string) {
	//通过支行名获取总行名和行号
	for _, transactionDetail := range transferDetailsList {
		detail := transactionDetail.Detail
		payingBankNames = append(payingBankNames, detail.BankName)
	}
	return
}
